package org.zhangkun.jmsg.ui.swing.view;

import java.awt.AWTException;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowFocusListener;
import java.awt.image.BufferedImage;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.awt.image.ImageProducer;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JPanel;

import org.zhangkun.jmsg.util.FileUtil;

/**
 * 截图
 * 
 * @author zhangkun
 * 
 */
public class ScreenCapturing extends JPanel {

	/**
	 * 缓存图片对象
	 */
	private BufferedImage screenImg;
	/**
	 * 完成图片的截取
	 */
	private boolean finishCapturing = false;
	/**
	 * 截图保存的路径
	 */
	private String file;
	/**
	 * 当前鼠标的坐标
	 */
	private Point currPoint = new Point();
	/**
	 * 鼠标按下时的坐标
	 */
	private Point pressedPoint = new Point();
	/**
	 * 鼠标是否按下
	 */
	private boolean isKeyPressed;
	/**
	 * 当前选中的区域
	 */
	private Rectangle selRect;
	/**
	 * 鼠标选定时的临时区域，就是鼠标松开前的选择区域
	 */
	private Rectangle tmpRect = new Rectangle();
	/**
	 * 窗体对象
	 */
	private JDialog dialog;
	/**
	 * 是否移动选中的区域
	 */
	private boolean moveSelRect;
	/**
	 * 移动时选中的偏移位置
	 */
	private Point offset = new Point();

	private ScreenCapturing() {
		dialog = new JDialog();
		dialog.setContentPane(this);
		// 取得屏幕大小
		Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
		try {
			// 截取屏幕
			screenImg = (new Robot()).createScreenCapture(new Rectangle(0, 0,
					(int) d.getWidth(), (int) d.getHeight()));
		} catch (AWTException e) {
			// TODO Auto-generated catch block
			finishCapturing = true;
			dialog.dispose();
			return;
		}
		dialog.setSize(d);
		// 取消窗体的边框
		dialog.setUndecorated(true);
		// 显示
		dialog.setVisible(true);
		dialog.addWindowFocusListener(new WindowFocusListener() {

			@Override
			public void windowLostFocus(WindowEvent e) {
				// TODO Auto-generated method stub
				// 如果失去焦点则请求焦点，请求失败则完成截图，返回null
				if (dialog.requestFocusInWindow())
					dialog.requestFocus();
				else {
					finishCapturing = true;
					dialog.dispose();
				}
			}

			@Override
			public void windowGainedFocus(WindowEvent e) {
				// TODO Auto-generated method stub

			}
		});
		dialog.addKeyListener(new KeyListener() {

			@Override
			public void keyTyped(KeyEvent e) {
				// TODO Auto-generated method stub

			}

			@Override
			public void keyReleased(KeyEvent e) {
				// TODO Auto-generated method stub
				if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
					back();
				}
				if (e.getKeyCode() == KeyEvent.VK_ENTER) {
					if (selRect != null) {
						finishCapturing();
					}
				}
			}

			@Override
			public void keyPressed(KeyEvent e) {
				// TODO Auto-generated method stub
			}
		});
		dialog.addMouseListener(new MouseListener() {

			@Override
			public void mouseReleased(MouseEvent e) {
				// TODO Auto-generated method stub
				if (e.getButton() == MouseEvent.BUTTON1) {
					if (selRect == null)
						selRect = new Rectangle(tmpRect);
					isKeyPressed = false;
				} else if (e.getButton() == MouseEvent.BUTTON3) {
					back();
				}
				repaint();
			}

			@Override
			public void mousePressed(MouseEvent e) {
				// TODO Auto-generated method stub
				if (e.getButton() == MouseEvent.BUTTON1) {
					pressedPoint.setLocation(e.getLocationOnScreen());
					currPoint.setLocation(e.getLocationOnScreen());
					isKeyPressed = true;
					if (selRect == null)
						updateTmpRect();
					else if (selRect.contains(pressedPoint)) {
						moveSelRect = true;
						offset.x = selRect.x - pressedPoint.x;
						offset.y = selRect.y - pressedPoint.y;
						updateSelRect();
					} else {
						moveSelRect = false;
					}
					repaint();
				}
			}

			@Override
			public void mouseExited(MouseEvent e) {
				// TODO Auto-generated method stub

			}

			@Override
			public void mouseEntered(MouseEvent e) {
				// TODO Auto-generated method stub

			}

			@Override
			public void mouseClicked(MouseEvent e) {
				// TODO Auto-generated method stub
				if (e.getClickCount() > 1) {
					if (selRect != null) {
						if (selRect.contains(e.getLocationOnScreen())) {
							finishCapturing();
						}
					}
				}
			}

		});
		dialog.addMouseMotionListener(new MouseMotionListener() {

			@Override
			public void mouseMoved(MouseEvent e) {
				// TODO Auto-generated method stub
			}

			@Override
			public void mouseDragged(MouseEvent e) {
				// TODO Auto-generated method stub
				// if (e.getButton() == MouseEvent.BUTTON1) {
				currPoint.setLocation(e.getLocationOnScreen());
				if (selRect == null)
					updateTmpRect();
				else if (moveSelRect)
					updateSelRect();
				repaint();
				// }
			}
		});
	}

	/**
	 * 调用截屏，该方法会阻塞当前线程，直到完成，如果截取成功则返回文件存放的路径，存放在临时文件中。如果截图取消或失败则返回null
	 * 
	 * @return
	 */
	public static String capturing() {
		return new ScreenCapturing().getFile();
	}

	public String getFile() {
		while (!finishCapturing) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return file;
	}

	private void back() {
		if (selRect == null) {
			finishCapturing = true;
			dialog.dispose();
		} else {
			selRect = null;
			repaint();
		}
	}

	@Override
	public void paint(Graphics g) {
		// TODO Auto-generated method stub
		g.drawImage(screenImg, 0, 0, this);
		Graphics2D g2d = (Graphics2D) g;
		if (selRect == null && !isKeyPressed) {
			g2d.setComposite(AlphaComposite.getInstance(
					AlphaComposite.SRC_OVER, 0.5f));
			g.setColor(Color.BLACK);
			g.fillRect(0, 0, getWidth(), getHeight());
		} else if (isKeyPressed && selRect == null) {
			g2d.setComposite(AlphaComposite.getInstance(
					AlphaComposite.SRC_OVER, 0.5f));
			g.setColor(Color.BLACK);
			g.fillRect(0, 0, getWidth(), tmpRect.y);
			g.fillRect(0, tmpRect.y, tmpRect.x, tmpRect.height);
			g.fillRect(0, tmpRect.y + tmpRect.height, getWidth(), getHeight()
					- (tmpRect.y + tmpRect.height));
			g.fillRect(tmpRect.x + tmpRect.width, tmpRect.y, getWidth()
					- (tmpRect.x + tmpRect.width), tmpRect.height);
			g2d.setComposite(AlphaComposite.getInstance(
					AlphaComposite.SRC_OVER, 1.0f));
			g.setColor(Color.blue);
			g2d.drawRect(tmpRect.x, tmpRect.y, tmpRect.width, tmpRect.height);

		} else if (selRect != null) {
			g2d.setComposite(AlphaComposite.getInstance(
					AlphaComposite.SRC_OVER, 0.5f));
			g.setColor(Color.BLACK);
			g.fillRect(0, 0, getWidth(), selRect.y);
			g.fillRect(0, selRect.y, selRect.x, selRect.height);
			g.fillRect(0, selRect.y + selRect.height, getWidth(), getHeight()
					- (selRect.y + selRect.height));
			g.fillRect(selRect.x + selRect.width, selRect.y, getWidth()
					- (selRect.x + selRect.width), selRect.height);
			g.setColor(Color.blue);
			g2d.drawRect(selRect.x, selRect.y, selRect.width, selRect.height);

		}
	}

	public void updateTmpRect() {
		int x, y;
		if (pressedPoint.x > currPoint.x)
			x = currPoint.x;
		else
			x = pressedPoint.x;
		if (pressedPoint.y > currPoint.y)
			y = currPoint.y;
		else
			y = pressedPoint.y;
		int w = Math.abs(pressedPoint.x - currPoint.x);
		int h = Math.abs(pressedPoint.y - currPoint.y);
		tmpRect.setBounds(x, y, w, h);
	}

	private void updateSelRect() {
		// TODO Auto-generated method stub
		selRect.x = currPoint.x + offset.x;
		selRect.y = currPoint.y + offset.y;

	}

	public static Image cutImg(MediaTracker tracker, BufferedImage img, int x,
			int y, int w, int h, JComponent com) {
		ImageProducer src = img.getSource();
		ImageFilter cut = new CropImageFilter(x, y, w, h);
		Image retImg = com.createImage(new FilteredImageSource(src, cut));

		tracker.addImage(retImg, 0);

		try {
			tracker.waitForAll();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return retImg;
	}

	private Image cutImg() {
		return cutImg(new MediaTracker(this), screenImg, selRect.x, selRect.y,
				selRect.width, selRect.height, this);
	}

	private void finishCapturing() {
		// TODO Auto-generated method stub

		try {
			File f = FileUtil.createTempFile(System.currentTimeMillis() + "",
					".png");
			ImageIO.write(createBufferedImage(cutImg()), "PNG",
					new FileOutputStream(f));
			file = f.getAbsolutePath();
			finishCapturing = true;
			dialog.dispose();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	private RenderedImage createBufferedImage(Image cutImg) {
		// TODO Auto-generated method stub
		BufferedImage img = new BufferedImage(cutImg.getWidth(this),
				cutImg.getHeight(this), BufferedImage.TYPE_4BYTE_ABGR);
		img.getGraphics().drawImage(cutImg, 0, 0, this);
		return img;
	}
}
